<?php defined('SYSPATH') or die('No direct script access.');

class RegistrationWizard_Controller extends WizardController {

	public function __construct() {
		parent::__construct(
				'RegistrationWizardData', /* data class name */
				'/user/registrationWizard', /* wizardPath */
				'user/registrationWizardLayout', /* contentLayout */
				RegistrationWizardData::$STEPS
		);
		if (($this->data == null || $this->data->seminar == null) && Router::$method != 'enter') {
			$this->redirect('/user/seminarChoice');
		}
		$this->activeMenuItem = UserMenu::$SEMINAR_CHOICE;
	}

	/* ------------------------------------------------------------------- */
	/* - Seminar														 - */
	/* ------------------------------------------------------------------- */

	public function enter() {
		$this->newData();
		// GET request from /user/seminarChoice
		$seminarId = $this->input->get('id');

		if (! valid::isId($seminarId)) {
			$this->msg->error('error.invalidId');
			$this->redirect('/user/seminarChoice');
			return;
		}

		$seminar = $this->dao->queryOne(
				'SELECT se.*, l10n.name, l10n.description ' .
				'FROM seminar se ' .
				'LEFT OUTER JOIN seminar_l10n l10n ON se.id = l10n.seminar_id AND l10n.language_code = :language_code ' .
				'WHERE se.id = :seminar_id',
				array(
					'language_code' => $this->getL10nLanguageCode(),
					'seminar_id' => $seminarId
				));
		if (! $seminar) {
			$this->msg->error('error-recordNotFound');
			$this->redirect('/user/seminarChoice');
			return;
		}
		
		// Bank account
		$seminar['bankAccount'] = $this->dao->getById('bank_account', $seminar['bank_account_id']);
		$this->data->seminar = $seminar;

		$this->data->isAfterDeadline = date::diffDates($this->data->seminar['registration_deadline'], date::today()) > 0;

		// Social discount. If the discount is available only before the deadline, check it.
		$socialDiscount = $this->dao->getSeminarSocialDiscount($this->data->seminar['id']);
		$this->data->socialDiscount = $socialDiscount;

		// Extra charges for late registration
		$this->data->earlyDiscount = $this->dao->getSeminarEarlyDiscount($this->data->seminar['id']);
		$this->data->lateCharge = $this->dao->getSeminarLateCharge($this->data->seminar['id']);
		$this->data->isEarlyDiscountApplied = $this->data->earlyDiscount && ! $this->data->isAfterDeadline;
		$this->data->isLateChargeApplied = $this->data->lateCharge && $this->data->isAfterDeadline;
		
		$this->redirect('/user/registrationWizard/step');
	}
	
	/* ------------------------------------------------------------------- */
	/* - Personal Data												   - */
	/* ------------------------------------------------------------------- */

	protected function personalDataStep() {
		$this->personalDataData();
	}
	
	protected function personalDataData() {
		$this->viewData['formData'] = $this->getAuthOrSubstituteUser();
		
		$this->viewData['countryOptions'] = $this->dao->optionsCountry(true);
		$this->viewData['idcardTypeOptions'] = form::idcardOptions();
		$this->viewData['papersRequired'] = seminarHelper::arePapersRequired($this->getAuthOrSubstituteUser('birth_date'));
	}

	protected function personalDataNext() {
		$formData = $this->postToDbValues();
		$this->viewData['formData'] = $formData;

		// Validation
		$validator = new EntityValidator($formData, 'person', $this->msg);
		if (seminarHelper::arePapersRequired($this->getAuthOrSubstituteUser('birth_date'))) {
			$validator->required('idcard_type');
			$validator->required('idcard_number');
		}
		$validator->required('citizenship_code');
		$validator->required('country_of_residence_code');
		
		if (! $formData['dataIsValid']) {
			$this->msg->error(text::get('registrationWizard-dataIsValid-required'));
		}
		
		if ($this->msg->hasErrors()) {
			return FALSE;
		}
		
		// If user changed his country of residence or ID card number, save it in the database.
		if ($formData['country_of_residence_code'] != $this->getAuthOrSubstituteUser('country_of_residence_code')
				|| $formData['idcard_number'] != $this->getAuthOrSubstituteUser('idcard_number')
				|| $formData['idcard_type'] != $this->getAuthOrSubstituteUser('idcard_type')
				|| $formData['citizenship_code'] != $this->getAuthOrSubstituteUser('citizenship_code')) {
			
			$person = $this->dao->getById('person', $this->getAuthOrSubstituteUser('id'));
			$person['country_of_residence_code'] = $formData['country_of_residence_code'];
			$person['citizenship_code'] = $formData['citizenship_code'];
			if ($formData['idcard_number'] && $formData['idcard_type']) {
				$person['idcard_number'] = $formData['idcard_number'];
				$person['idcard_type'] = $formData['idcard_type'];
			}
			$this->dao->update('person', $person);

			// Update session auth data
			$this->setUserField('country_of_residence_code', $formData['country_of_residence_code']);
			$this->setUserField('citizenship_code', $formData['citizenship_code']);
			if ($formData['idcard_number'] && $formData['idcard_type']) {
				$this->setUserField('idcard_number', $formData['idcard_number']);
				$this->setUserField('idcard_type', $formData['idcard_type']);
			}
		}
		
		// Find out which price group the logged in user belongs to.
		$countryCode = $this->getAuthOrSubstituteUser('country_of_residence_code');
		if (! $countryCode) {
			$countryCode = $this->getAuthOrSubstituteUser('country_code');
		}
		$this->data->priceGroup = $this->dao->queryOne('SELECT pg.* FROM price_group pg ' .
				'JOIN price_group_country cnt ON pg.id = cnt.price_group_id ' .
				'WHERE pg.seminar_id = :seminar_id AND cnt.country_code = :country_code',
				array(
						'seminar_id' => $this->data->seminar['id'],
						'country_code' => $countryCode
				));
		if ($this->data->priceGroup == NULL) {
			$uniqueValues = array('seminar_id' => $this->data->seminar['id'], 'is_default' => 1);
			$this->data->priceGroup = $this->dao->getUnique('price_group', $uniqueValues);
		}
		
		// Load up the currency object
		$this->data->priceGroup['currency'] = $this->dao->getByCode('currency', $this->data->priceGroup['currency_code']);
	}

	/* ------------------------------------------------------------------- */
	/* - Programs														- */
	/* ------------------------------------------------------------------- */

	/**
	 * Default action method.
	 */
	protected function programStep() {

		// Program overlap detection
		$dateWithProgramList = array();
		$programsOverlap = false;
		foreach ($this->data->selectedProgramList as $program) {
			if ($program['isShortProgram']) {
				if ($dateWithProgramList[$program['shortProgramDate']]) {
					$programsOverlap = TRUE;
					break;
				}
				else {
					$dateWithProgramList[$program['shortProgramDate']] = TRUE;
				}
			}
			else {
				$beginDate = strtotime($program['seminarBatch']['begin_date']);
				$endDate = strtotime($program['seminarBatch']['end_date']);
				$date = $beginDate;
				while ($date < $endDate) {
					if ($dateWithProgramList[$date]) {
						$programsOverlap = TRUE;
						break;
					}
					else {
						$dateWithProgramList[$date] = TRUE;
					}
					$date += 3600 * 24;
				}
			}
		}
		$this->viewData['programsOverlap'] = $programsOverlap;

		$this->programData();
	}

	protected function programData() {
	}

	protected function programNext() {

		// Validation
		if (valid::isEmpty($this->data->selectedProgramList)) {
			$this->msg->error('registrationWizard.error-chooseProgram');
			return FALSE;
		}
		
		// Find out if the user applies for normal program or for karmayoga.
		foreach ($this->data->selectedProgramList as $program) {
			echo $program['programType']['code'];
			if ($program['programType']['code'] == constants::$normalProgramTypeCode) {
				$this->data->appliesForStandardProgram = true;
			}
			if ($program['programType']['code'] == constants::$programTypeCodeKarmayoga) {
				$this->data->appliesForKarmayoga = true;
			}
		}
	}

	public function addProgramForm() {
		// Create map/tree $batchTypeList['batchList']['programTypeList']['accommodationTypeList']
		$this->viewData['batchTypeList'] = $this->dao->queryAll(
				'SELECT type.code, l10n.name, l10n.description ' .
				'FROM batch_type type ' .
				'LEFT OUTER JOIN batch_type_l10n l10n ON l10n.batch_type_code = type.code AND l10n.language_code = :language_code ' .
				'WHERE type.code IN (SELECT batch_type_code FROM batch b WHERE b.seminar_id = :seminar_id)',
				array('language_code' => $this->getL10nLanguageCode(), 'seminar_id' => $this->data->seminar['id']));
		
		$alreadySelectedBatchCodes = array();
		$alreadySelectedDays = array();
		foreach ($this->data->selectedProgramList as $program) {
			if ($program['batch']) {
				$alreadySelectedBatchCodes[] = $program['batch']['batch_code'];
			}
			if ($program['shortProgramDate']) {
				$alreadySelectedDays[] = $program['shortProgramDate'];
			}
		}
		
		foreach ($this->viewData['batchTypeList'] as &$batchType) {
			$query = 'SELECT b.*, l10n.name, l10n.description ' .
					'FROM batch b ' .
					'LEFT OUTER JOIN batch_l10n l10n ON l10n.batch_code = b.batch_code AND l10n.seminar_id = :seminar_id AND l10n.language_code = :language_code ' .
					'WHERE b.seminar_id = :seminar_id AND b.batch_type_code = :code ';
			if (count($alreadySelectedBatchCodes) > 0) {
				$query .= 'AND b.batch_code NOT IN (' . sql::inClauseValues($alreadySelectedBatchCodes) . ') ';
			}
			$query .= 'ORDER BY b.begin_date';
			
			$batchType['batchList'] = $this->dao->queryAll($query,
					array(
							'language_code' => $this->getL10nLanguageCode(),
							'seminar_id' => $this->data->seminar['id'],
							'code' => $batchType['code']
					)
			);
			
			foreach ($batchType['batchList'] as &$batch) {
				$batch['programTypeList'] = $this->dao->queryAll(
						'SELECT pt.code, l10n.name, l10n.description ' .
						'FROM available_program_type sbpt ' .
						'JOIN program_type pt on pt.code = sbpt.program_type_code ' .
						'LEFT OUTER JOIN program_type_l10n l10n ON l10n.program_type_code = sbpt.program_type_code AND l10n.language_code = :language_code ' .
						'WHERE sbpt.batch_code = :batch_code AND sbpt.seminar_id = :seminar_id ' .
						'ORDER BY pt.order_number',
						array(
								'seminar_id' => $batch['seminar_id'],
								'batch_code' => $batch['batch_code'],
								'language_code' => $this->getL10nLanguageCode()
						)
				);
				
				foreach ($batch['programTypeList'] as &$programType) {
					$programType['accommodationTypeList'] = $this->dao->queryAll(
							'SELECT cp.price, acc.code, l10n.name, l10n.description ' .
							'FROM category c ' .
							'JOIN category_price cp ON cp.category_code = c.category_code AND cp.seminar_id = c.seminar_id ' .
							'JOIN accomodation_type acc ON acc.code = c.accomodation_type_code ' .
							'LEFT OUTER JOIN accomodation_type_l10n l10n ON l10n.accomodation_type_code = c.accomodation_type_code AND l10n.language_code = :language_code ' .
							'WHERE c.batch_type_code = :batch_type_code ' .
							'AND c.program_type_code = :program_type_code ' . 
							'AND cp.price_group_id = :price_group_id ' .
							'AND c.seminar_id = :seminar_id ' .
							'ORDER BY acc.order_number',
							array(
								'price_group_id' => $this->data->priceGroup['id'],
								'seminar_id' => $this->data->seminar['id'],
								'batch_type_code' => $batchType['code'],
								'program_type_code' => $programType['code'],
								'language_code' => $this->getL10nLanguageCode()
							)
					);
				}
			}
		}
		$this->renderView('/user/registrationWizard/ajax/addProgramForm');
	}

	public function addProgram() {
		// batch_type_code -> batch_code -> program_type_code, accomodation_type_code

		$formData = $this->postToDbValues();

		if (! valid::isCode($formData['batch_type_code']) ||
				! valid::isCode($formData['batch_code']) ||
				! valid::isCode($formData['program_type_code']) ||
				! valid::isCode($formData['accomodation_type_code'])) {
			$this->msg->error('registrationWizard.addProgramError-validation');
			$this->redirectToStep();
		}

		$program = array();
		$program['batchType'] = $this->dao->getLocalizedEntityByCode('batch_type', $formData['seminarBatchTypeCode'], $this->getL10nLanguageCode());
		$program['batch'] = $this->dao->getLocalizedBatch($this->data->seminar['id'], $formData['batch_code'], $this->getL10nLanguageCode());
		$program['programType'] = $this->dao->getLocalizedEntityByCode('program_type', $formData['program_type_code'], $this->getL10nLanguageCode());
		$program['accomodationType'] = $this->dao->getLocalizedEntityByCode('accomodation_type', $formData['accomodation_type_code'], $this->getL10nLanguageCode());
		if (! $program['batchType'] || ! $program['batch'] || ! $program['programType'] || ! $program['accomodationType']) {
			$this->msg->error('error.recordNotFound');
			$this->redirectToStep();
		}

		// Read the price of this program
		$categoryPrice = $this->dao->queryOne(
				'SELECT cp.price, cp.category_code ' .
				'FROM category c ' .
				'JOIN category_price cp ON cp.category_code = c.category_code AND cp.seminar_id = c.seminar_id ' .
				'WHERE c.seminar_id = :seminar_id ' .
				'AND cp.price_group_id = :price_group_id ' .
				'AND c.batch_type_code = :batch_type_code ' .
				'AND c.accomodation_type_code = :accomodation_type_code ' .
				'AND c.program_type_code = :program_type_code',
				array(
						'seminar_id' => $this->data->seminar['id'],
						'price_group_id' => $this->data->priceGroup['id'],
						'batch_type_code' => $formData['batch_type_code'],
						'accomodation_type_code' => $formData['accomodation_type_code'],
						'program_type_code' => $formData['program_type_code']
				)
		);
		$program['price'] = $categoryPrice['price'];
		$program['category_code'] = $categoryPrice['category_code'];

		$this->data->selectedProgramList[] = $program;

		$this->redirectToStep();
	}

	public function removeProgram() {
		$index = $this->input->get('index');

		if (! valid::isInteger($index) || $index < 0) {
			$this->msg->error('error.invalidId');
			$this->redirectToStep();
		}

		unset($this->data->selectedProgramList[$index]);

		$this->msg->info('registrationWizard.programRemoved');
		$this->redirectToStep();
	}

	/* ------------------------------------------------------------------- */
	/* - Program specific info - exercise group, karmayoga type		  - */
	/* ------------------------------------------------------------------- */

	protected function programSpecificStep() {
		$this->programSpecificData();

		$formData = array('program_notes' => $this->data->programNotes);
		if ($this->data->exerciseGroup) {
			$formData['exercise_group_code'] = $this->data->exerciseGroup['code'];
		}
		if ($this->data->karmayogaType) {
			$formData['karmayoga_type_code'] = $this->data->karmayogaType['code'];
		}
		$this->viewData['formData'] = $formData;
	}

	protected function programSpecificData() {
		// Exercise group options
		if ($this->data->appliesForStandardProgram) {
			$this->viewData['exerciseGroupOptions'] = $this->dao->queryOptions('SELECT l10n.exercise_group_code AS code, l10n.name ' .
					'FROM available_exercise_group seg ' .
					'JOIN exercise_group_l10n l10n ON l10n.exercise_group_code = seg.exercise_group_code AND l10n.language_code = :language_code ' .
					'WHERE seg.seminar_id = :seminar_id',
					array('seminar_id' => $this->data->seminar['id'], 'language_code' => $this->getL10nLanguageCode()));
		}
		if ($this->data->appliesForKarmayoga) {
			$this->viewData['karmayogaTypeOptions'] = $this->dao->queryOptions('SELECT l10n.karmayoga_type_code AS code, l10n.name ' .
					'FROM available_karmayoga_type skt ' .
					'JOIN karmayoga_type_l10n l10n ON l10n.karmayoga_type_code = skt.karmayoga_type_code AND l10n.language_code = :language_code ' .
					'WHERE skt.seminar_id = :seminar_id',
					array('seminar_id' => $this->data->seminar['id'], 'language_code' => $this->getL10nLanguageCode()));
		}
	}
	
	protected function programSpecificNext() {
		$formData = $this->postToDbValues();

		$egCount = $this->dao->queryCount('SELECT count(*) FROM available_exercise_group seg WHERE seg.seminar_id = :seminar_id',
				array('seminar_id' => $this->data->seminar['id']));
		if ($egCount > 0) {
			if ($this->data->appliesForStandardProgram && ! valid::isCode($formData['exercise_group_code'])) {
				$this->msg->error('registrationWizard.error-chooseExerciseGroup');
				return FALSE;
			}

			if ($this->data->appliesForStandardProgram) {
				$this->data->exerciseGroup = $this->dao->getLocalizedEntityByCode(
						'exercise_group', $formData['exercise_group_code'], $this->getL10nLanguageCode());
			}
		}
		if ($this->data->appliesForKarmayoga && valid::isCode($formData['karmayoga_type_code'])) {
			$this->data->karmayogaType = $this->dao->getLocalizedEntityByCode(
					'karmayoga_type', $formData['karmayoga_type_code'], $this->getL10nLanguageCode());
		}
		$this->data->programNotes = $formData['program_notes'];
	}

	/* ------------------------------------------------------------------- */
	/* - Price - discounts and charges								   - */
	/* ------------------------------------------------------------------- */

	protected function priceStep() {
		$this->priceData();
	}

	protected function priceData() {
		$preliminaryPrice = 0;
		foreach ($this->data->selectedProgramList as $index => $program) {
			$programPrice = $program['price'];
			if ($this->data->isSocialDiscountApplied) {
				if ($program['programType']['code'] != constants::$programTypeCodeKarmayoga
						|| $this->data->socialDiscount['available_for_karmayoga']) {
					if ($program['programType']['code'] != 'children') {
						$programPrice = ($programPrice * (100 - $this->data->socialDiscount['percentage'])) / 100;
					}
				}
			}

			if ($this->data->isEarlyDiscountApplied) {
				if ($program['programType']['code'] != constants::$programTypeCodeKarmayoga 
						|| $this->data->earlyDiscount['applies_to_karmayoga']) {
					$programPrice = ($programPrice * (100 - $this->data->earlyDiscount['percentage'])) / 100;
				}
			}
			if ($this->data->isLateChargeApplied) {
				if ($program['programType']['code'] != constants::$programTypeCodeKarmayoga
						|| $this->data->lateCharge['applies_to_karmayoga']) {
					if (! $program['programType']['single_days_only'] || $this->data->lateCharge['applies_to_single_days']) {
						$programPrice = ($programPrice * (100 + $this->data->lateCharge['percentage'])) / 100;
					}
				}
			}
			$preliminaryPrice += $programPrice;
		}
		if ($this->data->extraDiscountForm) {
			$preliminaryPrice -= $this->data->extraDiscountForm['extra_discount'];
		}
		$this->data->preliminaryPrice = $preliminaryPrice;
	}

	protected function priceNext() {
	}
	
	public function extraDiscountForm() {
		$this->viewData['extraDiscountFormData'] = $this->data->extraDiscountForm;
		$this->viewData['selectedProgramOptions'] = array();
		foreach ($this->data->selectedProgramList as $index => $program) {
			$this->viewData['selectedProgramOptions'][$index] = $program['batch']['batch_code'] . ' - ' . $program['category_code'] . ' (' . format::price($program['price'], $this->data->priceGroup['currency_code']) . ')';
		}
		$this->renderView('/user/registrationWizard/ajax/extraDiscountForm');
	}
	
	public function extraDiscountSave() {
		$extraDiscountFormData = $this->postToDbValues();
		$this->viewData['extraDiscountFormData'] = $extraDiscountFormData;
		
		if ($extraDiscountFormData['extra_discount']) {
			$validator = new EntityValidator($extraDiscountFormData, 'registration');
			$validator->integer('programIndex', 'registrationWizard.extraDiscountProgramIndex');
			$validator->positiveInteger('extra_discount');
			$validator->required('extra_discount_reason');

			if (! $this->msg->hasErrors()) {
				$this->data->extraDiscountForm = $extraDiscountFormData;
				$this->msg->info('registration-extraDiscountHasBeenApplied', format::price($extraDiscountFormData['extra_discount'], $this->data->priceGroup['currency_code']));
			}
		}
		$this->redirect('/user/registrationWizard/step');
	}

	public function applySocialDiscount() {
		$this->data->isSocialDiscountApplied = TRUE;
		$this->redirect($this->stepUrl);
	}

	public function cancelSocialDiscount() {
		$this->data->isSocialDiscountApplied = FALSE;
		$this->redirect($this->stepUrl);
	}
	
	public function cancelExtraDiscount() {
		$this->data->extraDiscountForm = array();
		$this->msg->info('registrationWizard-extraDiscountCancelled');
		$this->redirect($this->stepUrl);
	}

	/* ------------------------------------------------------------------- */
	/* - Payment														 - */
	/* ------------------------------------------------------------------- */

	protected function paymentStep() {
		$paymentForm = array();
		if ($this->data->paymentForm) {
			$paymentForm = $this->data->paymentForm;
		}
		else {
			// Default values
			$paymentForm['paymentPlace'] = 'local';

			$userOrgId = $this->getAuthOrSubstituteUser('organization_id');
			if ($userOrgId) {
				$paymentAcceptance = $this->dao->getUnique('payment_acceptance', array('organization_id' => $userOrgId, 'seminar_id' => $this->data->seminar['id']));
				if ($paymentAcceptance && ! date::isInPast($paymentAcceptance['deadline'])) {
					$paymentForm['organization_id'] = $userOrgId;
					
					// If there is only one payment type option for the organization, select it.
					if ($paymentAcceptance['accepts_cash'] && ! $paymentAcceptance['accepts_bank_transfer']) {
						$paymentForm['payment_type'] = 'cash';
					}
					else if (! $paymentAcceptance['accepts_cash'] && $paymentAcceptance['accepts_bank_transfer']) {
						$paymentForm['payment_type'] = 'bank';
					}
					else if ($this->getSessionData()->getUserSubstitute() != null) {
						// If the user registers someone else, he will probably receive the payment in cash.
						$paymentForm['payment_type'] = 'cash';
					}
				}
			}
		}

		if ($paymentForm['country_code'] == NULL) {
			$paymentForm['country_code'] = $countryCode = $this->getAuthOrSubstituteUser('country_of_residence_code');
		}
		if ($this->data->paymentNotes) {
			$paymentForm['payment_notes'] = $this->data->paymentNotes;
		}
		
		$this->viewData['paymentForm'] = $paymentForm;
		$this->paymentData();
	}

	protected function paymentData() {
		$params = array(
				'country_code' => $this->getAuthOrSubstituteUser('country_of_residence_code'),
				'seminar_id' => $this->data->seminar['id'],
				'true' => sql::$TRUE);
		$query = 'SELECT org.*, pa.* ' .
				'FROM payment_acceptance pa ' .
				'JOIN organization org ON pa.organization_id = org.id ' .
				'WHERE org.country_code = :country_code ' .
				'AND pa.confirmed_at IS NULL ' .
				'AND pa.seminar_id = :seminar_id ' .
				'AND (pa.accepts_cash = :true OR pa.accepts_bank_transfer = :true) ';
		if (! $this->getAuthUser('is_admin')) {
			$query .= 'AND (pa.deadline >= :today ';
			$params['today'] = sql::$TODAY;
			if ($this->getAuthOrg()) {
				// Organization manager may accept registrations anytime.
				$query .= ' OR org.id = :orgId ';
				$params['orgId'] = $this->getAuthOrg('id');
			}
			$query .= ') ';
		}
		$query .= 'ORDER BY org.name';
		$this->viewData['organizationList'] = $this->dao->queryAll($query, $params);
		$this->viewData['organizationOptions'] = array('');
		$organizationIdList = array(0); // Zero to make sure the list is not empty - to avoid SQL syntax error in IN clause
		foreach ($this->viewData['organizationList'] as &$organization) {
			$organizationIdList[] = $organization['id'];
			if ($organization['bank_account_id']) {
				$organization['bank_account'] = $this->dao->getById('bank_account', $organization['bank_account_id']);
			}
			$this->viewData['organizationOptions'][$organization['id']] = $organization['name'];
		}
		
		// Select organizations that no longer accept payments
		$this->viewData['unavailableOrganizationList'] = $this->dao->queryAll(
				'SELECT org.* ' .
				'FROM payment_acceptance pa ' .
				'JOIN organization org ON pa.organization_id = org.id ' .
				'WHERE org.country_code = :country_code ' .
				'AND pa.seminar_id = :seminar_id ' .
				'AND (pa.accepts_cash = :true OR pa.accepts_bank_transfer = :true) ' .
				'AND org.id NOT IN (' . sql::inClauseValues($organizationIdList) . ') ' .
				'ORDER BY org.name',
				array(
						'country_code' => $this->getAuthOrSubstituteUser('country_of_residence_code'),
						'seminar_id' => $this->data->seminar['id'],
						'true' => sql::$TRUE
				));
		
		// Calculate the on arrival payment fee. The fee is forgiven if at least on of the following is true:
		// - there are only short programs selected
		// - user has no possibility to pay in his country of residence
		$this->data->paymentOnArrivalFee = 0;
		$registrationForShortProgramsOnly = true;
		foreach ($this->data->selectedProgramList as $program) {
			if (! $program['isShortProgram']) {
				$registrationForShortProgramsOnly = false;
				break;
			}
		}
		if (count($this->viewData['organizationList']) > 0 && ! $registrationForShortProgramsOnly) {
			$this->data->paymentOnArrivalFee = $this->data->seminar['payment_on_arrival_fee_' . strToLower($this->data->priceGroup['currency_code'])];
		}
	}

	protected function paymentNext() {
		$paymentForm = $this->postToDbValues();
		$this->viewData['paymentForm'] = $paymentForm;

		// Validation
		if ($paymentForm['paymentPlace'] != 'local' && $paymentForm['paymentPlace'] != 'onArrival') {
			$this->msg->error('registrationWizard.error-choosePaymentPlace');
		}
		else {
			if ($paymentForm['paymentPlace'] == 'local') {
				if (! valid::isId($paymentForm['organization_id'])) {
					$this->msg->error('registrationWizard.error-chooseOrganization');
				}
				else if ($paymentForm['payment_type'] != 'cash' && $paymentForm['payment_type'] != 'bank') {
					$this->msg->error('registrationWizard.error-choosePaymentType');
				}
			}
		}
		if ($this->msg->hasErrors()) {
			return FALSE;
		}

		if ($paymentForm['paymentPlace'] == 'local') {
			$paymentForm['country'] = $this->dao->getByCode('country', $this->getAuthOrSubstituteUser('country_of_residence_code'));
			$paymentForm['organization'] = $this->dao->getById('organization', $paymentForm['organization_id']);
			if ($paymentForm['payment_type'] == 'bank') {
				$paymentForm['paymentAcceptance'] = $this->dao->queryOne(
						'SELECT pa.* FROM payment_acceptance pa ' .
						'WHERE seminar_id = :seminar_id AND organization_id = :organization_id',
						array('seminar_id' => $this->data->seminar['id'], 'organization_id' => $paymentForm['organization_id']));
				$paymentForm['bankAccount'] = $this->dao->queryOne(
						'SELECT ba.* FROM bank_account ba ' .
						'WHERE ba.id = :bank_account_id',
						array('bank_account_id' => $paymentForm['paymentAcceptance']['bank_account_id']));
			}
		}
		else {
			$onArrivalPaymentOrg = $this->dao->getById('organization', Kohana::config('yosemin.onArrivalPaymentOrganizationId'));
			
			// Remove all info about organization a payment type from the form data
			$paymentForm = array(
					'paymentPlace' => $paymentForm['paymentPlace'],
					'payment_type' => 'onArrival',
					'organization' => $onArrivalPaymentOrg
			);
		}

		$this->data->paymentForm = $paymentForm;
		$this->data->paymentNotes = $paymentForm['payment_notes'];

		$this->data->paymentForm['payment_on_arrival_fee'] = NULL;
		
		// Calculate total price of the registration
		$this->data->totalPrice = $this->data->preliminaryPrice;
		if ($paymentForm['paymentPlace'] == 'onArrival' && $this->data->paymentOnArrivalFee) {
			$this->data->totalPrice += $this->data->paymentOnArrivalFee;
			$this->data->paymentForm['payment_on_arrival_fee'] = $this->data->paymentOnArrivalFee;
		}
	}

	public function savePaymentForm() {
		$paymentForm = $this->postToDbValues();
		$this->data->paymentForm = $paymentForm;
		$this->redirect('user/registrationWizard/step');
	}

	/* ------------------------------------------------------------------- */
	/* - Summary														 - */
	/* ------------------------------------------------------------------- */

	protected function summaryStep() {
		$this->summaryData();
	}

	protected function summaryData() {
	}

	protected function summaryNext() {
	}

	/* ------------------------------------------------------------------- */
	/* - Finish														  - */
	/* ------------------------------------------------------------------- */

	public function finish() {
		$this->dao->getDb()->beginTransaction();
		try {
			// Save each selected program as a registration
			$this->data->registrationIdList = array();
			foreach ($this->data->selectedProgramList as $index => &$program) {
				
				// Save the registration
				$registration = array(
						'seminar_id' => $this->data->seminar['id'],
						'category_code' => $program['category_code'],
						'batch_code' => $program['batch']['batch_code'],
						'person_id' => $this->getAuthOrSubstituteUser('id'),
						'price_group_id' => $this->data->priceGroup['id'],
						'total_price' => $this->data->totalPrice,
						'social_discount_applied' => sql::boolean($this->data->isSocialDiscountApplied),
						'early_discount_applied' => sql::boolean($this->data->isEarlyDiscountApplied),
						'late_charge_applied' => sql::boolean($this->data->isLateChargeApplied),
						'payment_organization_id' => $this->data->paymentForm['organization']['id'],
						'payment_type' => $this->data->paymentForm['payment_type'],
						'exercise_group_code' => ($this->data->exerciseGroup ? $this->data->exerciseGroup['code'] : NULL),
						'preferred_karmayoga_type_code' => ($this->data->karmayogaType ? $this->data->karmayogaType['code'] : NULL),
						'program_notes' => $this->data->programNotes,
						'payment_notes' => $this->data->paymentNotes,
						'payment_on_arrival_fee' => $this->data->paymentForm['payment_on_arrival_fee']
				);
				if ($this->data->extraDiscountForm && $index == $this->data->extraDiscountForm['programIndex']) {
					$registration['extra_discount'] = $this->data->extraDiscountForm['extra_discount'];
					$registration['extra_discount_reason'] = $this->data->extraDiscountForm['extra_discount_reason'];
				}
				$program['registration_id'] = $this->dao->insert('registration', $registration);
				$this->data->registrationIdList[] = $program['registration_id'];
			}

			// Commit the transaction
			$this->dao->getDb()->commit();
		}
		catch (Exception $e) {
			// If something raised an exception in our transaction block of statements,
			// roll back any work performed in the transaction
			$this->dao->getDb()->rollBack();
			throw $e;
			return;
		}

		$regIdListString = join(',', $this->data->registrationIdList);
		
		// Send a confirmation email to the user.
		$userEmailLang = $this->getAuthOrSubstituteUser('preferred_language');
		$emailBodyParams = array(
			$this->data->seminar['name'],
			format::decimal($this->data->totalPrice) . ' ' . text::getInLang($userEmailLang, 'currency.mark-' . $this->data->priceGroup['currency_code']),
			text::getInLang($userEmailLang, 'registration.paymentType-' . $this->data->paymentForm['payment_type'])
		);
		if ($this->data->paymentForm['payment_type'] == 'bank') {
			$bankPaymentDetails = '';
			if (count($this->data->registrationIdList) > 1) {
				$bankPaymentDetails .= text::getInLang($userEmailLang, 'registrationWizard-confirmationEmail-moreRegs');
			}
			$bankPaymentDetails = text::getInLang($userEmailLang, 'bankAccount.number') . ': ' . $this->data->paymentForm['bankAccount']['number'] . '/' . $this->data->paymentForm['bankAccount']['bank_number'] . "\n" .
					text::getInLang($userEmailLang, 'paymentAcceptance.variable_symbol') . ': ' . $this->data->paymentForm['paymentAcceptance']['variable_symbol'] . "\n";
			if (count($this->data->registrationIdList) > 1) {
				$bankPaymentDetails .= text::getInLang($userEmailLang, 'registrationWizard-confirmationEmail-regNumbers') . ': ' . $regIdListString . "\n";
			}
			else {
				$bankPaymentDetails .= text::getInLang($userEmailLang, 'myRegistration-specific_symbol') . ': ' . $regIdListString . "\n";
			}
			$emailBodyParams[] = $bankPaymentDetails;
		}
		else {
			$emailBodyParams[] = "\n";
		}
		$emailPerson = $this->getAuthOrSubstituteUser();
		$mailBody = text::getInLang($userEmailLang, 'registrationWizard-confirmationEmail-body', $emailBodyParams);
		$mailResult = email::sendInUtf8(
				$emailPerson['first_name'] . ' ' . $emailPerson['last_name'],
				$emailPerson['email'],
				text::getInLang($userEmailLang, 'registrationWizard.confirmationEmail-title', $regIdListString),
				email::addHeadingAndClosing($mailBody, $emailPerson, $userEmailLang));
		if (! $mailResult) {
			$this->msg->warning('registrationWizard.mailFailedRegistrationValid');
		}

		// Send info email to admin that there is a new registration
		/* We don't really care until the registration is confirmed 
		if (! $this->getAuthUser('is_admin')) {
			$mailResult = email::sendInUtf8(Kohana::config('yosemin.registrationManager-name'),
					Kohana::config('yosemin.registrationManager-mail'),
					'Nová přihláška na seminář: ' . $this->data->seminar['name'],
					'Jméno: ' . format::personFullName($this->getAuthOrSubstituteUser()) . "\n" .
					'Čísla přihlášek: ' . $regIdListString);
			if (! $mailResult) {
			}
		}*/

		// Send an email to the organization that will accept the payment
		if ($this->data->paymentForm['organization']['emails_enabled'] && $this->data->paymentForm['organization']['email']) {
			$org = $this->data->paymentForm['organization'];
			$orgEmailLang = $org['preferred_language'];
			$emailBody = text::getInLang($orgEmailLang, 'registratinWizard-orgMail-body',
					$this->data->seminar['name'],
					format::personFullName($this->getAuthOrSubstituteUser()),
					$regIdListString);
			$orgEmailLang = $org['preferred_language'];
			$mailResult = email::sendInUtf8($org['name'], $org['email'],
					text::getInLang($orgEmailLang, 'registratinWizard-orgMail-subject'),
					$emailBody);
			if (! $mailResult) {
				// TODO warning message
			}
		}

		$this->redirect('/user/registrationWizard/success');
	}

	public function success() {
		if (! $this->data) {
			$this->redirectToStep();
		}
		$this->contentLayout = 'user/userLayout';
		$this->viewData['regConfirmationForm'] = array(
				'registration_ids' => join(',', $this->data->registrationIdList),
				'endUserSubstitution' => sql::$TRUE
		);
		$this->renderSubview('user/registrationWizard/wizardSuccess');
		$this->clearData();
	}
}